﻿using BaseFramework.ConnectionProvider;
using BaseFramework.Core;
using BaseFramework.DbConnectionProvider;
using LiteFramework.Server.Component;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

namespace BaseFramework.Test
{
    class Program
    {
        /// <summary>
        /// 自动信号量：收到信号时，停止操作
        /// </summary>
        static AutoResetEvent autoRestEvent = new AutoResetEvent(false);
        static Dictionary<string, string> settings_MsSQL = new Dictionary<string, string>();
        static Dictionary<string, string> settings_MsSQL2 = new Dictionary<string, string>();
        static Dictionary<string, string> settings_MySQL = new Dictionary<string, string>();
        static Win32.ConsoleCtrlDelegate consoleDelegete = null;
        static void Main(string[] args)
        {
            #region init
            InstallConsoleHandle();
            Console.Title = "Haode.BaseFromawork 测试程序______________【Ctrl+C】中断当前操作";
            Console.SetWindowPosition(0, 0);
            Console.BufferHeight = 2000;

            int maxWidth = 160;
            int maxHeight = 100;

            // 设置宽度
            bool isError = true;
            do
            {
                try
                {
                    Console.WindowWidth = maxWidth--;
                    isError = false;
                }
                catch { }
            } while (isError);

            // 设置高度
            isError = true;
            do
            {
                try
                {
                    Console.WindowHeight = maxHeight--;
                    isError = false;
                    Console.WindowHeight = maxHeight--;
                }
                catch { }
            } while (isError);

            //改变控制台程序初始DOS位置
            IntPtr intptr = Win32.GetCurrentWindowHandle();
            Rect rect = new Rect();
            var re = Win32.GetWindowRect(intptr, out rect);
            int x = 0;
            int y = 0;
            int nWidth = rect.right - rect.left;
            int nHeight = rect.bottom - rect.top;
            Win32.MoveWindow(intptr, x, y, nWidth, nHeight, true);

            //string sqlKey = null;
            //string connStr = null;
            //string driver = null;

            //sqlKey = "Ms SQL";
            //connStr = getConnectionStr("MsSQL"); //"Persist Security Info=False;server=.\\DevR2;database=TestDB;User ID=sa;password=123456;Packet Size=4096;Pooling=true;Max Pool Size=100;Min Pool Size=1";
            //driver = "DbDriver.MsSqlDriver, Haode.DbDriver.MsSqlDriver";
            //settings_MsSQL.Clear();
            //settings_MsSQL.Add("Key", sqlKey);
            //settings_MsSQL.Add("ConnectionString", connStr);
            //settings_MsSQL.Add("ConnectionDriver", driver);

            //sqlKey = "Ms SQL2";
            //connStr = getConnectionStr("MsSQL"); //"Persist Security Info=False;server=.\\DevR2;database=TestDB;User ID=sa;password=123456;Packet Size=4096;Pooling=true;Max Pool Size=100;Min Pool Size=1";
            //driver = "DbDriver.MsSqlDriver, Haode.DbDriver.MsSqlDriver";
            //settings_MsSQL2.Clear();
            //settings_MsSQL2.Add("Key", sqlKey);
            //settings_MsSQL2.Add("ConnectionString", connStr);
            //settings_MsSQL2.Add("ConnectionDriver", driver);

            //sqlKey = "My SQL";
            //connStr = getConnectionStr("MySQL"); //"server=127.0.0.1;user id=root; password=123456; database=TestDB; pooling=false;port=3306";
            //driver = "DbDriver.MySqlDriver, Haode.DbDriver.MySqlDriver";
            //settings_MySQL.Clear();
            //settings_MySQL.Add("Key", sqlKey);
            //settings_MySQL.Add("ConnectionString", connStr);
            //settings_MySQL.Add("ConnectionDriver", driver);



            string sqlKey = null;
            string connStr = null;
            string dialect = null;
            string providerName = null;

            sqlKey = "Ms SQL";
            connStr = getConnectionStr("MsSQL"); //"Persist Security Info=False;server=.\\DevR2;database=TestDB;User ID=sa;password=123456;Packet Size=4096;Pooling=true;Max Pool Size=100;Min Pool Size=1";
            providerName = getProviderName("MsSQL");
            dialect = "Dialect.MsSqlDialect, Haode.Dialect.MsSqlDialect";
            settings_MsSQL.Clear();
            settings_MsSQL.Add("Key", sqlKey);
            settings_MsSQL.Add("ConnectionString", connStr);
            settings_MsSQL.Add("ProviderName", providerName);
            settings_MsSQL.Add("DialectClass", dialect);

            sqlKey = "Ms SQL2";
            connStr = getConnectionStr("MsSQL"); //"Persist Security Info=False;server=.\\DevR2;database=TestDB;User ID=sa;password=123456;Packet Size=4096;Pooling=true;Max Pool Size=100;Min Pool Size=1";
            providerName = getProviderName("MsSQL");
            dialect = "Dialect.MsSqlDialect, Haode.Dialect.MsSqlDialect";
            settings_MsSQL2.Clear();
            settings_MsSQL2.Add("Key", sqlKey);
            settings_MsSQL2.Add("ConnectionString", connStr);
            settings_MsSQL2.Add("ProviderName", providerName);
            settings_MsSQL2.Add("DialectClass", dialect);

            sqlKey = "My SQL";
            connStr = getConnectionStr("MySQL"); //"server=127.0.0.1;user id=root; password=123456; database=TestDB; pooling=false;port=3306";
            providerName = getProviderName("MySQL");
            dialect = "Dialect.MySqlDialect, Haode.Dialect.MySqlDialect";
            settings_MySQL.Clear();
            settings_MySQL.Add("Key", sqlKey);
            settings_MySQL.Add("ConnectionString", connStr);
            settings_MySQL.Add("ProviderName", providerName);
            settings_MySQL.Add("DialectClass", dialect);


            int totalInsert = getAppSettings("totalInsert", 200000);
            #endregion

            bool isTurnBack = false;
            while (true)
            {
                try
                {
                    Console.Clear();
                    Console.WriteLine();
                    Console.WriteLine();
                    WriteLine("　→ 菜单：数据库类型", ConsoleColor.DarkYellow);
                    Console.WriteLine("===================================================");
                    Console.WriteLine();
                    writeMenuItem("１", "MsSQL");
                    Console.WriteLine();
                    writeMenuItem("２", "MySQL");
                    Console.WriteLine();
                    Console.WriteLine();
                    writeMenuItem("其他键", "默认");
                    Console.WriteLine();
                    Console.WriteLine("===================================================");
                    Console.WriteLine();
                    Write("请选择：", ConsoleColor.DarkYellow);
                    var key = Console.ReadKey().KeyChar.ToString();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    switch (key)
                    {
                        case "1":
                        case "１":
                            // Ms SQL
                            isTurnBack = SqlTest(settings_MsSQL, totalInsert);
                            break;
                        case "2":
                        case "２":
                            // My SQL
                            isTurnBack = SqlTest(settings_MySQL, totalInsert);
                            break;
                        default:
                            // 默认测试
                            isTurnBack = false;
                            SqlTest_Auto(settings_MsSQL, settings_MySQL, totalInsert);
                            break;
                    }
                }
                catch (Exception ex)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(ex);
                    Console.ResetColor();
                    Console.WriteLine();
                }

                if (!isTurnBack)
                {
                    Console.WriteLine();
                    Write("\t按回车返回 ...", ConsoleColor.DarkYellow);
                    Console.ReadLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="settings"></param>
        /// <param name="totalInsert"></param>
        /// <returns>返回true，返回主动返回上一页</returns>
        static bool SqlTest(Dictionary<string, string> settings, int totalInsert)
        {
            bool isTurnBack = false; // 是否返回上一级
            string sqlType = settings["Key"];
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine(string.Format("========== {0} ==========", sqlType));
            Console.ForegroundColor = ConsoleColor.White;

            Console.WriteLine("    创建连接提供器...");
            var connectionProvider = ConnectionProviderFactory.Instance.Create(sqlType, settings);


            /***************************************/



            string operate = null;
            try
            {
                UserInfoComponent comp = new UserInfoComponent(connectionProvider);
                UserInfo newUser = genNewUser();
                // 增
                operate = "增加";
                var addResult = comp.Create(newUser);
                WriteLine(operate + "：" + addResult + "\tID：" + newUser.Id, ConsoleColor.Red);
                // 改
                operate = "修改";
                newUser.UserType = 1;
                var modResult = comp.Update(newUser);
                WriteLine(operate + "：" + addResult + "\tID：" + newUser.Id, ConsoleColor.Red);
                // 查
                operate = "查询";
                var getResult = comp.Get(newUser.Id);
                WriteLine(operate + "：" + (getResult != null) + "\tID：" + (getResult != null ? getResult.Id.ToString() : "<null>"), ConsoleColor.Red);
                // 删 
                operate = "删除";
                var delResult = comp.Delete(newUser);
                WriteLine(operate + "：" + delResult + "\tID：" + newUser.Id, ConsoleColor.Red);

                var model = comp.Get(1000);
                var modelList = comp.GetList(Expression.Or(Expression.Eq("Id", 1000), Expression.Eq("Id", 1001)));
                var modelList2 = comp.GetList(Expression.Gt("Id", 1000), 1, 20);
            }
            catch (Exception ex)
            {
                WriteLine(operate + " 数据失败：" + ex.Message, ConsoleColor.Red);
            }
            /***************************************/


            try
            {
                while (true)
                {
                    bool isKeyReg = true; // 默认为指令已注册
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    WriteLine(string.Format("　→ 菜单：操作类型（{0}）", sqlType), ConsoleColor.DarkYellow);
                    Console.WriteLine();
                    Console.WriteLine("===================================================");
                    Console.WriteLine();
                    writeMenuItem("１", "查询数据");
                    Console.WriteLine();
                    writeMenuItem("２", "插入数据");
                    Console.WriteLine();
                    writeMenuItem("３", "修改数据");
                    Console.WriteLine();
                    writeMenuItem("４", "删除数据");
                    Console.WriteLine();
                    Console.WriteLine();
                    writeMenuItem("０", "返回");
                    Console.WriteLine();
                    Console.WriteLine("===================================================");
                    Console.WriteLine();
                    Write("请选择：", ConsoleColor.DarkYellow);
                    var key = Console.ReadKey().KeyChar.ToString();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine();
                    switch (key)
                    {
                        case "1":
                        case "１":
                            // 查询数据
                            {
                                int seq = 0;
                                for (int i = 0; i < 20; i++)
                                {
                                    new Thread(() =>
                                    {
                                        int mySeq = Interlocked.Increment(ref seq);
                                        if (mySeq % 2 == 0)
                                            Sql_GetList(connectionProvider, 1, 300, 100, "_this.Id desc", true, string.Format("【线程{0}】", mySeq.ToString().PadLeft(2, ' ')));
                                        else
                                            Sql_GetList(ConnectionProviderFactory.Instance.Create(settings_MsSQL2["Key"], settings_MsSQL2), 1, 300, 100, "_this.Id desc", true, string.Format("【线程{0}】", mySeq.ToString().PadLeft(2, ' ')));
                                    }).Start();
                                }
                            }
                            break;
                        case "2":
                        case "２":
                            // 插入数据
                            {
                                int seq = 0;
                                for (int i = 0; i < 20; i++)
                                {
                                    new Thread(() =>
                                    {
                                        int mySeq = Interlocked.Increment(ref seq);
                                        WriteLine("线程开始：" + mySeq, ConsoleColor.DarkCyan);
                                        Sql_Insert(connectionProvider, totalInsert, string.Format("【线程{0}】", mySeq.ToString().PadLeft(2, ' ')));
                                        WriteLine("\t\t线程结束：" + mySeq, ConsoleColor.Cyan);
                                    }).Start();
                                }
                            }
                            break;
                        case "3":
                        case "３":
                            // 删除数据
                            {
                                int seq = 0;
                                for (int i = 0; i < 20; i++)
                                {
                                    new Thread(() =>
                                    {
                                        int mySeq = Interlocked.Increment(ref seq);
                                        var list = Sql_GetList(connectionProvider, 500, 300, 1, "_this.Id desc", true);
                                        Sql_Update(connectionProvider, list, string.Format("【线程{0}】", mySeq.ToString().PadLeft(2, ' ')));
                                    }).Start();
                                }
                            }
                            break;
                        case "4":
                        case "４":
                            // 删除数据
                            {
                                int seq = 0;
                                for (int i = 0; i < 20; i++)
                                {
                                    new Thread(() =>
                                    {
                                        int mySeq = Interlocked.Increment(ref seq);
                                        var list = Sql_GetList(connectionProvider, 500, 300, 1, "_this.Id desc", true);
                                        Sql_Delete(connectionProvider, list, string.Format("【线程{0}】", mySeq.ToString().PadLeft(2, ' ')));
                                    }).Start();
                                }
                            }
                            break;
                        case "0":
                        case "０":
                            isTurnBack = true;
                            break;
                        default:
                            isKeyReg = false;
                            break;
                    }

                    if (isTurnBack)
                    {
                        break;
                    }
                    else if (isKeyReg)
                    {
                        Console.WriteLine();
                        Write("\t按回车返回 ...", ConsoleColor.DarkYellow);
                        Console.ReadLine();
                        Console.WriteLine();
                        Console.WriteLine();
                        Console.WriteLine();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex);
                Console.ResetColor();
                Console.WriteLine();
            }

            if (!isTurnBack)
            {
                Console.WriteLine();
                Write("\t按回车返回 ...", ConsoleColor.DarkYellow);
                Console.ReadLine();
                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine();
            }

            return isTurnBack;
        }

        static void SqlTest_Auto(Dictionary<string, string> msSqlSettings, Dictionary<string, string> mySqlSettings, int totalInsert)
        {
            Action<Dictionary<string, string>> action = (settings) =>
            {
                if (settings == null) return;
                string sqlType = settings["Key"];
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.WriteLine(string.Format("========== {0} ==========", sqlType));
                Console.ForegroundColor = ConsoleColor.White;

                Console.WriteLine("    创建连接提供器...");
                var connectionProvider = ConnectionProviderFactory.Instance.Create(sqlType, settings);

                // 查询数据
                var list = Sql_GetList(connectionProvider, 500, 200, 1000, "_this.Id desc", true);
                // 插入数据
                Sql_Insert(connectionProvider, totalInsert);
                // 更新数据
                Sql_Update(connectionProvider, list);
                // 删除数据
                Sql_Delete(connectionProvider, list);
            };

            action(msSqlSettings);
            action(mySqlSettings);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connectionProvider"></param>
        /// <param name="fromPage">开始页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="pageCount">获取的总页码</param>
        /// <param name="orderBy">排序</param>
        /// <param name="quiet">安静模式。true时，不需要交互</param>
        /// <returns></returns>
        static IList<UserInfo> Sql_GetList(IDbConnectionProvider connectionProvider, int fromPage = 500, int pageSize = 200, int pageCount = 1000, string orderBy = "_this.Id", bool quiet = false, string logPre = null)
        {
            Console.WriteLine();
            Console.WriteLine(">>>>>>> 准备查找数据----------------------------------------------");
            if (!quiet)
            {
                Console.WriteLine();
                Write("\t请输入开始页码（直接回车使用默认页码）：", ConsoleColor.DarkYellow);
                var input = Console.ReadLine();
                int.TryParse(input, out fromPage);
            }

            if (fromPage <= 0) fromPage = 1;

            Console.WriteLine();
            WriteLine(string.Format("\t准备从第 {0} 页开始读取数据，每次读取 {1} 条数据，共读取 {2} 页", fromPage, pageSize, pageCount), ConsoleColor.DarkGray);
            Console.WriteLine();
            Stopwatch sw = new Stopwatch();
            IList<UserInfo> userList = null;
            long lastElapsedMilliseconds = 0;
            int totalResult = 0;
            double minAvg = double.MaxValue;
            double maxAvg = double.MinValue;
            int seq = 0;
            autoRestEvent.Reset();
            while (seq < pageCount)
            {
                if (autoRestEvent.WaitOne(0)) break;
                int currentPage = fromPage + seq++;
                sw.Start();
                while (true)
                {
                    try
                    {
                        userList = PersistentEntityMediator<UserInfo>.GetList(connectionProvider, null, currentPage, pageSize, orderBy, true);
                        break;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                    }
                }
                sw.Stop();
                if (userList == null || userList.Count == 0)
                {
                    if (seq == 1)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        writeSqlLog("无适合条件的数据");
                    }
                    break;
                }
                else
                {
                    var currTimeCost = sw.ElapsedMilliseconds - lastElapsedMilliseconds;
                    var currentResult = userList.Count;
                    var totalTimeCost = sw.ElapsedMilliseconds;
                    totalResult += currentResult;
                    lastElapsedMilliseconds = sw.ElapsedMilliseconds;

                    var currAvg = 1.00 * currTimeCost / currentResult;
                    if (minAvg > currAvg) minAvg = currAvg;
                    if (maxAvg < currAvg) maxAvg = currAvg;

                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(" {0}{1}\t读取第 {2} 页，共 {3} 条数据，耗时 {4} ms，平均 {5:F3} ms/条（最少 {6:F3} ms）\t 累计 {7} 条，耗时 {8} ms，平均 {9:F3} ms/条"
                        , logPre
                        , string.Format("[{0}/{1}]", seq, pageCount)//string.Format("[{0}/{1}]", seq, pageCount).PadLeft(pageCount.ToString().Length * 2 + 5, ' ')
                        , currentPage.ToString().PadLeft(pageCount.ToString().Length, ' ')
                        , currentResult
                        , currTimeCost.ToString().PadLeft(4, ' ')
                        , (1.00 * currTimeCost / currentResult).ToString("F3").PadLeft(5, ' ')
                        , minAvg
                        , totalResult
                        , totalTimeCost.ToString().PadLeft(4, ' ')
                        , (1.00 * totalTimeCost / totalResult).ToString("F3").PadLeft(5, ' '));
                }
            }

            Console.ResetColor();
            Console.WriteLine();
            if (seq > 1)
                Console.WriteLine(string.Format("\t 总耗时：{0} ms（{1:F3} min）\t\t平均最少耗时 [{2:F3}] ms\t\t平均最多耗时：{3:F3} ms", sw.ElapsedMilliseconds, 1.0 * sw.ElapsedMilliseconds / 60000, minAvg, maxAvg));
            else
                Console.WriteLine(string.Format("\t 总耗时：{0} ms（{1:F3} min）", sw.ElapsedMilliseconds, 1.0 * sw.ElapsedMilliseconds / 60000));
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("<<<<<<< 查找数据结束----------------------------------------------");

            return userList;
        }

        static IList<UserInfo> Sql_Search(IDbConnectionProvider connectionProvider)
        {
            var search = PersistentEntityMediator<UserInfo>.GetList(
                connectionProvider,
                Expression
                    .And(
                        Expression.Eq("BookName", "进化论"),
                        Expression.Eq("UType.MemberType_Id", 19))
                    .Or(Expression.Eq("UType.Name", "散户/临客")));

            writeSqlLog("---------------------------------------------------------");
            writeSqlLog("    搜索...");
            return PersistentEntityMediator<UserInfo>.GetList(connectionProvider);
        }

        static void Sql_Insert(IDbConnectionProvider connectionProvider, int totalInsert, string logPre = null)
        {
            Console.WriteLine();
            Console.WriteLine(">>>>>>> 准备插入数据----------------------------------------------");
            Console.WriteLine();
            int count = 0;
            double minAvg = float.MaxValue;
            double maxAvg = float.MinValue;
            long lastElapsedMilliseconds = 0;
            Action<string, string, string, ConsoleColor, ConsoleColor> write = (left, split, right, color1, color2) =>
            {
                Write(left, color1);
                Write(split, ConsoleColor.DarkYellow);
                Write(right, color2);
            };

            Stopwatch sw = new Stopwatch();
            autoRestEvent.Reset();
            WriteLine(string.Format("\t准备插入 {0} 条数据 ...", totalInsert), ConsoleColor.DarkGray);
            Console.WriteLine();
            while (count < totalInsert)
            {
                #region action ...
                if (autoRestEvent.WaitOne(0)) break;
                sw.Start();
                Sql_Insert(connectionProvider);
                sw.Stop();

                count++;
                if (count % 100 == 0)
                {
                    var curr = sw.ElapsedMilliseconds - lastElapsedMilliseconds;
                    lastElapsedMilliseconds = sw.ElapsedMilliseconds;

                    Write(string.Format(" {0}插入总数量", logPre), ConsoleColor.DarkCyan);

                    Write(" -> ");

                    Write(count + "/" + totalInsert, ConsoleColor.Cyan);

                    double currAvg = 1.00 * curr / 100;
                    double totalAvg = 1.00 * sw.ElapsedMilliseconds / count;
                    if (minAvg > currAvg) minAvg = currAvg;
                    if (maxAvg < currAvg) maxAvg = currAvg;

                    write("\t本批次耗时", "：", string.Format("{0} ms，", curr).PadLeft(8, ' '), ConsoleColor.DarkMagenta, ConsoleColor.Magenta);
                    write("  平均耗时", "：", string.Format("{0:F3} ms（最少 {1:F3} ms）", currAvg.ToString("F3").PadLeft(6, ' '), minAvg), ConsoleColor.DarkGreen, ConsoleColor.Green);

                    write("\t  累计耗时", "：", string.Format("{0} ms，", sw.ElapsedMilliseconds).PadLeft(10, ' '), ConsoleColor.DarkMagenta, ConsoleColor.Magenta);
                    write("  累计平均耗时", "：", string.Format("{0:F3} ms", totalAvg.ToString("F3").PadLeft(6, ' ')), ConsoleColor.DarkGreen, ConsoleColor.Green);
                    Console.WriteLine();
                }
                #endregion
            }
            Console.ResetColor();
            Console.WriteLine();
            Console.WriteLine(string.Format("\t 总耗时：{0} ms（{1:F3} min）\t\t平均耗时最少 [{2:F3}] ms\t\t平均耗时最多：{3:F3} ms", sw.ElapsedMilliseconds, 1.0 * sw.ElapsedMilliseconds / 60000, minAvg, maxAvg));
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("<<<<<<< 插入数据结束----------------------------------------------");
            Console.WriteLine();
            Console.WriteLine();
        }
        static void Sql_Insert(IDbConnectionProvider connectionProvider)
        {
            writeSqlLog("---------------------------------------------------------");
            writeSqlLog("    新建...");
            {
                var newUser = new UserInfo
                {
                    Name = "Heyd" + DateTime.Now.Millisecond,
                    Sex = SexEnum.Male,
                    UserType = 2,
                    Age = 25,
                    Desc = "Desc" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                    Test1 = "Test 1",
                    Test2 = "Test 2",
                    Test3 = "Test 3：AABBCC112233",
                    Test4 = "Test 4：AABBCC112233",
                    Test5 = DateTime.Now,
                    Test6 = "Test 6：AABBCC112233",
                    Test7 = 1234.5678M,
                    Test8 = long.MaxValue / 10 - 9893749,
                    Test9 = new byte[4],
                    Test10 = DateTime.Now.Second % 2 == 0,
                    Test11 = DateTime.Now,
                    Test12 = new DateTimeOffset(DateTime.Now),
                    Test13 = 123.45F,
                    Test14 = "Test 14：AABBCC112233",
                    Test15 = Guid.NewGuid(),
                    Test16 = 123456,
                    Test17 = new byte[10],
                    Test18 = "Test 18：AABBCC112233",
                    Test19 = "Test 19：AABBCC112233",
                    Test20 = "Test 20：AABBCC112233",
                };

                string err = null;
                if (PersistentEntityMediator<UserInfo>.Save(connectionProvider, newUser, out err))
                    writeSqlLog(string.Format("    新用户Id：{0}", newUser.Id));
                else
                    writeSqlLog(string.Format("    保存失败：{0}", newUser.Id));
            }
        }

        static void Sql_Update(IDbConnectionProvider connectionProvider, IList<UserInfo> userList, string logPre = null)
        {
            writeSqlLog("---------------------------------------------------------");
            writeSqlLog("    修改...");
            if (userList != null && userList.Count > 0)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                foreach (var user in userList)
                {
                    string err = null;

                    object oldVersion = user.TimeStamp;
                    user.Desc = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffff");
                    bool succ = PersistentEntityMediator<UserInfo>.Update(connectionProvider, user, out err, true);
                    if (succ)
                        writeSqlLog(string.Format("    修改成功！ID：{0}，TimeStamp：{1} -> {2}", user.Id, Tools.ToString(oldVersion), Tools.ToString(user.TimeStamp)));
                    else
                        writeSqlLog(string.Format("    修改失败！ID：{0}", user.Id));
                }
                sw.Stop();
                WriteLine(string.Format("\t 修改 {0} 条数据，总耗时：{1} ms（{2:F3} min），平均 {3:F3} ms/条", userList.Count, sw.ElapsedMilliseconds, 1.0 * sw.ElapsedMilliseconds / 60000, 1.0 * sw.ElapsedMilliseconds / userList.Count), ConsoleColor.Cyan);
            }
            else
            {
                writeSqlLog("    不存在历史数据！");
            }

            writeSqlLog();
            writeSqlLog("<<<<<<< 修改结束----------------------------------------------");
            writeSqlLog();
            writeSqlLog();
        }

        static void Sql_Delete(IDbConnectionProvider connectionProvider, IList<UserInfo> userList, string logPre = null)
        {
            writeSqlLog("---------------------------------------------------------");
            writeSqlLog("    删除...");
            if (userList != null && userList.Count > 0)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                foreach (var user in userList)
                {
                    string err = null;
                    if (PersistentEntityMediator<UserInfo>.Delete(connectionProvider, user, out err))
                        writeSqlLog(string.Format("    删除成功！ID：{0}", user.Id));
                    else
                        writeSqlLog(string.Format("    删除失败！ID：{0}", user.Id));
                }
                sw.Stop();
                WriteLine(string.Format("\t 删除 {0} 条数据，总耗时：{1} ms（{2:F3} min），平均 {3:F3} ms/条", userList.Count, sw.ElapsedMilliseconds, 1.0 * sw.ElapsedMilliseconds / 60000, 1.0 * sw.ElapsedMilliseconds / userList.Count), ConsoleColor.Cyan);
            }
            else
            {
                writeSqlLog("    不存在历史数据（历史数据少于3条）！");
            }

            writeSqlLog();
            writeSqlLog("<<<<<<< 删除结束----------------------------------------------");
            writeSqlLog();
            writeSqlLog();
        }

        /// <summary>
        /// 获取指定文件夹下所有子目录及文件函数
        /// </summary>
        /// <param name="theDir">指定目录</param>
        /// <param name="nLevel">默认起始值,调用时,一般为0</param>
        /// <param name="rn">用于迭加的传入值,一般为空</param>
        /// <returns></returns>
        public static string ListTreeShow(DirectoryInfo theDir, int nLevel, string rn)
        {
            if (theDir == null)
            {
                throw new ArgumentNullException("theDir");
            }
            //获得目录
            DirectoryInfo[] subDirectories = theDir.GetDirectories();
            foreach (DirectoryInfo dirinfo in subDirectories)
            {

                if (nLevel == 0)
                {
                    rn += "├";
                }
                else
                {
                    var s = string.Empty;
                    for (int i = 1; i <= nLevel; i++)
                    {
                        s += "│ ";
                    }
                    rn += s + "├";
                }
                rn += dirinfo.Name + System.Environment.NewLine;
                //目录下的文件
                var fileInfo = dirinfo.GetFiles();
                foreach (FileInfo fInfo in fileInfo)
                {
                    if (nLevel == 0)
                    {
                        rn += "│ ├";
                    }
                    else
                    {
                        var f = string.Empty;
                        for (int i = 1; i <= nLevel; i++)
                        {
                            f += "│ ";
                        }
                        rn += f + "│ ├";
                    }
                    rn += fInfo.Name.ToString() + System.Environment.NewLine;
                }
                rn = ListTreeShow(dirinfo, nLevel + 1, rn);


            }
            return rn;
        }

        static string getConnectionStr(string key)
        {
            return System.Configuration.ConfigurationManager.ConnectionStrings[key].ConnectionString;
        }
        static string getProviderName(string connStringName)
        {
            return System.Configuration.ConfigurationManager.ConnectionStrings[connStringName].ProviderName;
        }
        static string getAppSettings(string key)
        {
            if (System.Configuration.ConfigurationManager.AppSettings.AllKeys.Contains(key))
                return System.Configuration.ConfigurationManager.AppSettings[key];
            else
                return null;
        }
        static int getAppSettings(string key, int _default = -1)
        {
            string str = getAppSettings(key);
            int result = 0;
            if (int.TryParse(str, out result))
                return result;
            else
                return _default;
        }

        /// <summary>
        /// 安装事件处理程序
        /// </summary>
        static void InstallConsoleHandle()
        {
            consoleDelegete = new Win32.ConsoleCtrlDelegate(HandlerRoutine);

            bool bRet = Win32.SetConsoleCtrlHandler(consoleDelegete, true);
            if (bRet == false) //安装事件处理失败
            {
                Console.WriteLine("安装事件处理失败");
            }
            else
            {
                Console.WriteLine("安装事件处理成功");
            }
        }
        /// <summary>
        /// 处理程序例程，在这里编写对指定事件的处理程序代码
        /// 注意：在VS中调试执行时，在这里设置断点，但不会中断；会提示：无可用源；
        /// </summary>
        ///<param name="CtrlType">
        /// <returns></returns>
        static bool HandlerRoutine(int ctrlType)
        {
            switch (ctrlType)
            {
                case Win32.CTRL_C_EVENT:
                    //Console.WriteLine("C");
                    if (autoRestEvent != null) autoRestEvent.Set(); // 发送信号
                    return true; //这里返回true，表示阻止响应系统对该程序的操作
                //break;
                case Win32.CTRL_BREAK_EVENT:
                    //Console.WriteLine("BREAK");
                    break;
                case Win32.CTRL_CLOSE_EVENT:
                    //Console.WriteLine("CLOSE");
                    break;
                case Win32.CTRL_LOGOFF_EVENT:
                    //Console.WriteLine("LOGOFF");
                    break;
                case Win32.CTRL_SHUTDOWN_EVENT:
                    //Console.WriteLine("SHUTDOWN");
                    break;
            }
            //return true;//表示阻止响应系统对该程序的操作
            return false;//忽略处理，让系统进行默认操作
        }

        static UserInfo genNewUser()
        {
            return new UserInfo()
            {
                #region
                Name = "Hekainy",
                Age = 18,
                Sex = SexEnum.Male,
                UserType = 3,
                Desc = "Test 04-19 09:06",
                Test1 = "1",
                Test2 = "2",
                Test3 = "3",
                Test4 = "4",
                Test5 = DateTime.Now,
                Test6 = "6",
                Test7 = 12.34M,
                Test8 = 12345678,
                Test9 = Encoding.UTF8.GetBytes("Test9"),
                Test10 = true,
                Test11 = DateTime.Now,
                Test12 = new DateTimeOffset(DateTime.Now),
                Test13 = 123.456,
                Test14 = "14",
                Test15 = Guid.NewGuid(),
                Test16 = 123.45F,
                Test17 = Encoding.UTF8.GetBytes("hekainy - Test17"),
                Test18 = "18",
                Test19 = "19",
                Test20 = "20",
                #endregion
            };
        }

        /// <summary>
        /// 将数据库中timestamp转换成十六进制字符串
        /// </summary>
        /// <paramname="objTs">从数据库中获取的timestamp值</param>      
        /// <returns>timestamp十六进制字符串</returns>
        static string TimestampToString(object objTs)
        {
            byte[] bytes = objTs as byte[];
            string str = "0x" + BitConverter.ToString(bytes).Replace("-", "");
            return str;
        }

        ///<summary>
        ///将十六进制字符串转换成数据库的timestamp
        ///</summary>
        ///<paramname="str">timestamp十六进制字符串（支持“-”分隔符）</param>
        ///<returns>数据库的timestamp值</returns>
        static byte[] StringToTimestamp(string str)
        {
            if (string.IsNullOrEmpty(str)) return null;

            if (str.IndexOf('-') > 0)
            {
                string[] strSplit = str.Split('-');
                byte[] bytes = new byte[strSplit.Length];
                for (int i = 0; i < strSplit.Length; i++)
                {
                    bytes[i] = byte.Parse(strSplit[i], System.Globalization.NumberStyles.AllowHexSpecifier);
                }
                //string str2 = System.Text.Encoding.Default.GetString(bytes);
                return bytes;
            }
            else
            {
                if (str.StartsWith("0x")) str = str.Substring(2);
                byte[] bytes = new byte[str.Length / 2];
                for (int i = 0; i < str.Length; i += 2)
                {
                    bytes[i / 2] = byte.Parse(str.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
                }
                //string str2 = System.Text.Encoding.Default.GetString(bytes);
                return bytes;
            }
        }

        static void writeMenuItem(string menuKey, string menuContent)
        {
            if (menuKey == null) menuKey = string.Empty;

            var oldColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.Write(menuKey.PadLeft(10, ' '));
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.Write("\t：");
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine(menuContent);
            Console.ForegroundColor = oldColor;
        }
        static void writeSqlLog(object obj = null)
        {
            //Console.WriteLine(obj);
        }
        static object write_Lock = new object();

        static void Write(string msg)
        {
            Write(msg, Console.ForegroundColor);
        }
        static void Write(string msg, ConsoleColor color)
        {
            if (string.IsNullOrEmpty(msg)) return;
            lock (write_Lock)
            {
                var oldColor = Console.ForegroundColor;
                Console.ForegroundColor = color;
                Console.Write(msg);
                Console.ForegroundColor = oldColor;

            }
        }
        static void WriteLine(string msg, ConsoleColor color)
        {
            Write(msg, color);
            Console.WriteLine();
        }
    }
}